<?php

/************** Classe Abstraite              *********************************/
/******************************************************************************/
/*
    Date:       Février 2012
    Auteur:     Mickael Tourbot
    Version:    1.0

    Used:       extends ClassBase (like 'Class_Exemple')

*/
/******************************************************************************/
/******************************************************************************/

abstract    class           Classe_Base {

    /* Variables Statiques ****************************************************/
    protected static        $_tbl_name      = 'nom_de_la_table';
    protected static        $_prefix        = 'prefix_de_la_table';
    protected static        $_pk_name       = 'primary_key_de_la_table';
    

    /* PropriÃ©tÃ©s privÃ©es *****************************************************/
    /* @var $_db Classe_Bdd */
    protected               $_db            = NULL;
    protected               $_datas         = array();
    protected               $_isSelected    = FALSE;

    /**************************************************************************/
    /*  Constructeur **********************************************************/
    /**************************************************************************/

    public function         __construct($db, $id) {
        // On regarde les erreurs.
        if (!($db instanceof Classe_Bdd))
            throw new Exception($this->error_prefixe()." __construct() :: La bdd n'est pas bonne");

        $this->_db = $db;
        
        //Si l'id est renseigné, on va chercher les informations de l'objet pour constituer le tableau de données
        if ($id != null)
            $this->init($id);
        else
            $this->create_datas();
    }

    
    
    /**************************************************************************/
    /*  BDD - LECTURE
    /**************************************************************************/

    //On construit le tableau de données datas
    protected function      create_datas(){
        // On formate les champs a choisir. (Si aucun n'est dÃ©finie, on prend tout)
        $fields_str = '*';

        // On formate la requete
        $req = "SHOW COLUMNS FROM ".static::$_tbl_name;
        
        $liste_champs = $this->_db->fetchAll($req);
        
        $liste_nom_champs = array();
        
        foreach($liste_champs as $champ)
            $liste_nom_champs[$champ['Field']] = "";
        
        $this->_datas = $liste_nom_champs;

        
        // On vérifie que la requete est valide
        if (!$this->_datas) {
            throw new Exception($this->error_prefixe()." init() :: Erreur lors de la récupération des données de l'objet");
        }
    }
    
    // On récupère les données de l'objet
    protected function      init($id) {
        // On formate les champs a choisir. (Si aucun n'est dÃ©finie, on prend tout)
        $fields_str = '*';

        // On formate la requete
        $req = 'SELECT '.$fields_str.' FROM '.static::$_tbl_name.' WHERE '.static::$_pk_name.' = '.$id.' LIMIT 1';
        $this->_datas = $this->_db->fetchRow($req);

        // On vérifie que la requete est valide
        if ($this->_datas) {
            $this->_isSelected = TRUE;
        } else {
            throw new Exception($this->error_prefixe()." init() :: Erreur lors de la récupération des données de l'objet");
        }
    }
    
    
    
    
    
    /**************************************************************************/
    /*  BDD - ECRITURE
    /**************************************************************************/
   
    public function         save() {

        // On regarde si notre object a Ã©tÃ© construit a partir d'une requete SELECT
        if ($this->_isSelected){
            // oui >    On fait un update
            //die('update');
            return $this->update();
        }
        else{
            //die('insert');
            // non >    On crÃ©e une nouvelle entrÃ© dans la base
            return $this->insert();
        }
    }
    
    protected function      insert() {

        // Varaibles
        $data   = $this->_datas;
        $db     = $this->_db;

        // Error
        if (!$data)
            throw new Class_Exception('Update is not possible without data');

        // On forme la requete : req1 champs, req2 valeurs
        $req1 = NULL;
        $req2 = NULL;
        $sql = 'INSERT INTO `'.static::$_tbl_name.'` ';

        $i = 0;
        foreach ($data as $key => $val){
            if ($key != static::$_pk_name){
                if($i != 0){
                    $req1 .= ", ";
                    $req2 .= ", ";
                }
                $req1 .= $key;
                $req2 .= "'".Classe_Securite::bdd($val)."'";
                $i++;
            }
        }

        $sql .= '('.$req1.') VALUES ('.$req2.');';
        $query = $db->query($sql);

        // Maintenant qu'il est dans la base on peut le passer en SELETED
        $this->_datas[static::$_pk_name] = $db->last_id();
        $this->_isSelected = TRUE;

        // On retourne le resultat de la requete
        return $query;
    }
    
    protected function      update() {

        // Variables
        $data       = $this->_datas;
        $db         = $this->_db;

        // Error
        if (!$data)
            throw new Class_Exception('Update is not possible without data');
        if (!isset($data[static::$_pk_name]))
            throw new Class_Exception('Update is not possible without ID');

        // On forme la requete
        $req = NULL;
        $sql = "UPDATE ".static::$_tbl_name." SET ";

        $i = 0;
        foreach ($data as $key => $val){
            if ($key != static::$_pk_name){
                if($i != 0)
                    $req .= ", ";
                if($val == null)
                    $req .= $key." = null";
                else
                    $req .= $key." = '".Classe_Securite::bdd($val)."'";
                $i++;
            }
        }

        $sql .= $req;
        $sql .= " WHERE ".static::$_pk_name." = ".$data[static::$_pk_name];
        
        
        $query = $db->query($sql);
        
        
        // On retourne la valeur de retour de la requete
        return $query;
    }
    
    
    public function         delete() {
        // Variables
        $db     = $this->_db;
        $data   = $this->_datas;

        // Check erreur
        if (!$this->_isSelected)
            throw new Exception($this->error_prefixe()." delete() :: L'objet que vous essayez de supprimer n'est pas crée");

        // On forme la requete
        $sql = "DELETE FROM ".static::$_tbl_name." WHERE ".static::$_pk_name." = ".$data[static::$_pk_name];
        $query = $db->query($sql);

        // On vÃ©rifie le retour de la requete
        if (!$query) {
            // Une foreign key bloque la suppression.
            if ($db->errorCode() == '23000')
                throw new Exception($this->error_prefixe()." delete():: Impossible de supprimer, cet objet est bloqué par une clé étrangère");
        }

        // On retourne un SUCCESS
        return TRUE;
    }
    
    

    /**************************************************************************/
    /*  Utilitaires ***********************************************************/
    /**************************************************************************/

    static function         count($db) {
        $sql = 'SELECT COUNT(*) AS nb FROM '.self::$_tbl_name;
        return $db->fetchOne($sql);
    }

    protected function      isSelect() {
        return $this->_isSelected;
    }
    
    private function        error_prefixe(){
        return "Classe_Base :: Objet <b>'".static::$_tbl_name."'</b> ::";
    }

    
    /**************************************************************************/
    /*  Magic Methodes ********************************************************/
    /**************************************************************************/
    
    /* Méthode magique qui récupère une donnée de l'objet 
     * Example utilisation : echo $objet->nom_champs;
     */
    public function         __get($name){
        //On vérifie si on essai pas de getter une clé étrangère
        if(substr(strtolower($name), 0, 2) != "fk"){
            //On ajoute le préfix de la table
            $name = static::$_prefix.$name;
        }
        
        if (array_key_exists(strtolower($name), $this->_datas)) {
            return $this->_datas[strtolower($name)];
        }
        else
            throw new Exception($this->error_prefixe()." __get() :: Erreur lors de la récupération d'une donnée ('".strtolower($name)."') de l'objet '".static::$_tbl_name."' : <b>'".static::$_tbl_name."['".strtolower($name)."']'</b>");
    }
    
    /*
     * Méthode magique qui set une valeur de l'objet
     * Example utilisation : $objet->nom_champs = "test";
     */
    public function         __set($name, $value)
    {
        //On vérifie si on essai pas de setter une clé étrangère
        if(substr(strtolower($name), 0, 2) != "fk"){
            //On ajoute le préfix de la table
            $name = static::$_prefix.$name;
        }
        
        // On set la donnée dans le tableau de datas
        if (array_key_exists(strtolower($name), $this->_datas)) {
            $this->_datas[strtolower($name)] = $value;
        }
        else
            throw new Exception($this->error_prefixe()." __set() :: Erreur lors de la modification d'une donnée ('".strtolower($name)."') de l'objet '".static::$_tbl_name."' : <b>'".static::$_tbl_name."['".strtolower($name)."']'</b>");
    }
    
    public function         getId(){
        return $this->_datas[static::$_pk_name];
    }
}
?>

